home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Mac / Demo / speech / grail.py next >
Text File  |  1994-10-02  |  5KB  |  229 lines

  1. # Pass this program the Holy Grail script on stdin.
  2. import sys
  3. import string
  4. import stdwin
  5. from stdwinevents import *
  6.  
  7. try:
  8.     import macspeech
  9. except ImportError:
  10.     macspeech = None
  11.  
  12. WINWIDTH = 1000
  13. scrw, scrh = stdwin.getscrsize()
  14. if WINWIDTH > 0.8*scrw:
  15.     WINWIDTH = int(0.8*scrw)
  16. BLACK = stdwin.fetchcolor('black')
  17. RED = stdwin.fetchcolor('red')
  18. BLUE = stdwin.fetchcolor('blue')
  19.  
  20. done='done'
  21.  
  22. class MacSpeaker:
  23.     def __init__(self):
  24.         self.voices = []
  25.         self.nvoices = macspeech.CountVoices()
  26.         self.curvoice = 1
  27.         self.rate = 1.0
  28.         
  29.     def _newvoice(self):
  30.         vd = macspeech.GetIndVoice(self.curvoice)
  31.         sc = vd.NewChannel()
  32.         self.curvoice = self.curvoice + 1
  33.         if self.curvoice > self.nvoices:
  34.             self.curvoice = 1
  35.         return sc
  36.         
  37.     def newvoices(self, n):
  38.         self.voices = []
  39.         for i in range(n):
  40.             self.voices.append(self._newvoice())
  41.         if self.rate <> 1.0:
  42.             self.setrate(1.0)
  43.             
  44.     def setrate(self, factor):
  45.         self.rate = self.rate*factor
  46.         for v in self.voices:
  47.             r = v.GetRate()
  48.             v.SetRate(r*factor)
  49.                     
  50.     def speak(self, i, text):
  51.         self.voices[i-1].SpeakText(text)
  52.         
  53.     def busy(self):
  54.         return macspeech.Busy()
  55.  
  56. [NOTHING, NEWSCENE, ACT, TEXT, MORETEXT] = range(5)
  57. def parseline(line):
  58.     stripline = string.strip(line)
  59.     if not stripline:
  60.         return NOTHING, ''
  61.     if stripline[:5] == 'Scene':
  62.         return NEWSCENE, stripline
  63.     if line[0] == '[':
  64.         return ACT, stripline
  65.     if line[0] == ' ' and ':' in line:
  66.         splitline = string.splitfields(stripline, ':')
  67.         stripline = string.joinfields(splitline[1:], ':')
  68.         return TEXT, (splitline[0], string.strip(stripline))
  69.     return MORETEXT, stripline
  70.  
  71. def readscript(file):
  72.     lines = file.readlines()
  73.     acts = []
  74.     actor_dict = {}
  75.     longest = 0
  76.     prev_act = 0
  77.     for i in range(len(lines)):
  78.         tp, data = parseline(lines[i])
  79.         if tp == NEWSCENE:
  80.             acts.append(actor_dict.keys(), lines[prev_act:i])
  81.             prev_act = i
  82.             actor_dict = {}
  83.         elif tp == TEXT:
  84.             actor_dict[data[0]] = 1
  85.         lines[i] = tp, data
  86.     return acts[1:]
  87.  
  88. class Main:
  89.     def __init__(self):
  90.         if macspeech:
  91.             self.speaker = MacSpeaker()
  92.         else:
  93.             self.speaker = None
  94.         sys.stdin = open('SCRIPT', 'r')
  95.         self.acts = readscript(sys.stdin)
  96.         maxactor = 0
  97.         for actorlist, actdata in self.acts:
  98.             if len(actorlist) > maxactor:
  99.                 maxactor = len(actorlist)
  100.         if not self.loadnextact():
  101.             print 'No acts to play!'
  102.             raise done
  103.         self.lh = stdwin.lineheight()
  104.         self.winheight = (maxactor+2)*self.lh
  105.         stdwin.setdefwinsize(WINWIDTH, self.winheight)
  106.         self.win = stdwin.open('The Play')
  107.         self.win.setdocsize(WINWIDTH, self.winheight)
  108.         self.win.change(((0,0),(WINWIDTH, self.winheight)))
  109.         self.menu = self.win.menucreate('Play')
  110.         self.menu.additem('Faster', '+')
  111.         self.menu.additem('Slower', '-')
  112.         self.menu.additem('Quit', 'Q')
  113.         self.speed = 4
  114.         
  115.     def done(self):
  116.         del self.win
  117.         del self.menu
  118.  
  119.     def loadnextact(self):
  120.         if not self.acts: return 0
  121.         actors, lines = self.acts[0]
  122.         del self.acts[0]
  123.         prevactor = 0
  124.         for i in range(len(lines)):
  125.             tp, data = lines[i]
  126.             if tp == NOTHING:
  127.                 continue
  128.             elif tp in (NEWSCENE, ACT):
  129.                 lines[i] = 0, data
  130.             elif tp == TEXT:
  131.                 prevactor = actors.index(data[0])
  132.                 lines[i] = prevactor+1, data[1]
  133.             else:
  134.                 lines[i] = prevactor+1, data
  135.         self.lines = lines
  136.         self.actors = [''] + actors
  137.         self.actorlines = [''] * len(self.actors)
  138.         if self.speaker:
  139.             self.speaker.newvoices(len(self.actors)-1)
  140.         self.prevline = 0
  141.         self.actwidth = 0
  142.         for a in self.actors:
  143.             w = stdwin.textwidth(a)
  144.             if w > self.actwidth:
  145.                 self.actwidth = w
  146.         return 1
  147.  
  148.     def loadnextline(self):
  149.         if not self.lines: return 0
  150.         self.actorlines[self.prevline] = ''
  151.         top = self.lh*self.prevline
  152.         self.win.change(((0, top), (WINWIDTH, top+self.lh)))
  153.         line, data = self.lines[0]
  154.         del self.lines[0]
  155.         self.actorlines[line] = data
  156.         self.prevline = line
  157.         top = self.lh*self.prevline
  158.         self.win.change(((0, top), (WINWIDTH, top+self.lh)))
  159.         if line == 0:
  160.             self.win.settimer(5*self.speed)
  161.         else:
  162.             if self.speaker:
  163.                 self.speaker.speak(line, data)
  164.                 tv = 1
  165.             else:
  166.                 nwords = len(string.split(data))
  167.                 tv = self.speed*(nwords+1)
  168.             self.win.settimer(tv)
  169.         return 1
  170.  
  171.     def timerevent(self):
  172.         if self.speaker and self.speaker.busy():
  173.             self.win.settimer(1)
  174.             return
  175.         while 1:
  176.             if self.loadnextline(): return
  177.             if not self.loadnextact():
  178.                 stdwin.message('The END')
  179.                 self.win.close()
  180.                 raise done
  181.             self.win.change(((0,0), (WINWIDTH, self.winheight)))
  182.  
  183.     def redraw(self, top, bottom, draw):
  184.         for i in range(len(self.actors)):
  185.             tpos = i*self.lh
  186.             bpos = (i+1)*self.lh-1
  187.             if tpos < bottom and bpos > top:
  188.                 draw.setfgcolor(BLUE)
  189.                 draw.text((0, tpos), self.actors[i])
  190.                 if i == 0:
  191.                     draw.setfgcolor(RED)
  192.                 else:
  193.                     draw.setfgcolor(BLACK)
  194.                 draw.text((self.actwidth+5, tpos), self.actorlines[i])
  195.  
  196.     def run(self):
  197.         self.win.settimer(10)
  198.         while 1:
  199.             ev, win, arg = stdwin.getevent()
  200.             if ev == WE_DRAW:
  201.                 ((left, top), (right, bot)) = arg
  202.                 self.redraw(top, bot, self.win.begindrawing())
  203.             elif ev == WE_TIMER:
  204.                 self.timerevent()
  205.             elif ev == WE_CLOSE:
  206.                 self.win.close()
  207.                 raise done
  208.             elif ev == WE_MENU and arg[0] == self.menu:
  209.                 if arg[1] == 0:
  210.                     if self.speed > 1:
  211.                         self.speed = self.speed/2
  212.                         if self.speaker:
  213.                             self.speaker.setrate(1.4)
  214.                 elif arg[1] == 1:
  215.                     self.speed = self.speed * 2
  216.                     if self.speaker:
  217.                         self.speaker.setrate(0.7)
  218.                 elif arg[1] == 2:
  219.                     self.win.close()
  220.                     raise done
  221.  
  222. if 1:
  223.     main = Main()
  224.     try:
  225.         main.run()
  226.     except done:
  227.         pass
  228.     del main
  229.